package com.xc.file.config;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xc.core.enums.EffectStatus;
import com.xc.file.entity.FileEntity;
import com.xc.file.entity.FileHashEntity;
import com.xc.file.enums.FileSuffix;
import com.xc.file.mapper.FileHashMapper;
import com.xc.file.model.FileModel;
import com.xc.file.model.HashModel;
import com.xc.file.model.ServerModel;
import com.xc.file.model.ServerSpaceModel;
import com.xc.file.service.FileCacheService;
import com.xc.file.service.FileService;
import com.xc.file.service.UploadService;
import com.xc.tool.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * <p>启动成功执行</p>
 *
 * @author xc
 * @version v1.0.0
 */
@Component
@Slf4j
public class StartSuccess implements CommandLineRunner {
    @Autowired
    private Constants constants;
    @Autowired
    private FileHashMapper fileHashMapper;
    @Autowired
    private FileService fileService;
    @Autowired
    private FileCacheService fileCacheService;
    @Autowired
    private UploadService uploadService;

    @Override
    public void run(String... strings) {
        try {
            deleteTempFile();
            updateServerInfo();
            initUpdateCreateFileHash();
            initVerifyFileHash();
            timingTask();
        } catch (Exception e) {
            log.error("文件装载失败！" + e.getMessage(), e);
            e.printStackTrace();
        }
    }

    /**
     * <p>定时任务</p>
     */
    private void timingTask() {
        try {
            Runnable runnable = new Runnable() {
                //创建 run 方法
                public void run() {
                    deleteTempFile();
                    constants.setFileInfoTable(new Hashtable<>());
                    initVerifyFileHash();
                    updateServerInfo();
                    log.info("定时清除数据完成！");
                }
            };
            ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
            Calendar cal = Calendar.getInstance();
            //每天定点执行
            cal.set(Calendar.HOUR_OF_DAY, 23);
            cal.set(Calendar.MINUTE, 59);
            cal.set(Calendar.SECOND, 59);
            // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
            service.scheduleAtFixedRate(runnable, cal.getTime().getTime() - new Date().getTime(), 1, TimeUnit.DAYS);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * <p>初始化删除文件</p>
     */
    private void deleteTempFile() {
        try {
            // 清理临时文件
            for (FolderConfig folderConfig : constants.getFolderPaths()) {
                File[] array = new File(folderConfig.getPath()).listFiles();
                if (array != null) {
                    for (File file : array) {
                        if (file.isFile()) {
                            String hashCode = file.getName().substring(0, file.getName().indexOf("."));
                            // 删除上传中的零时文件
                            String tempPath = folderConfig.getPath() + File.separator + hashCode + FileSuffix.UPLOAD.getSuffix();
                            File tempFile = new File(tempPath);
                            if (tempFile.exists() && !tempFile.delete()) {
                                log.error("初始化删除上传中的零时文件失败！");
                            }
                            // 删除打包的零时文件
                            String packPath = folderConfig.getPath() + File.separator + hashCode + FileSuffix.PACK.getSuffix();
                            File packFile = new File(packPath);
                            if (packFile.exists() && !packFile.delete()) {
                                log.error("初始化删除打包的零时文件失败！");
                            }
                        }
                    }
                }
            }
            // 清理临时目录
            if (!FileUtils.deleteFolder(constants.getTempFolder().getPath())) {
                log.error("清理临时目录失败！");
            }
            log.info("清理临时信息完成！");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * <p>更新FileMode信息</p>
     */
    private void updateServerInfo() {
        //计算可用空间
        List<ServerSpaceModel> serverSpaceModels = new ArrayList<>();
        for (FolderConfig folderConfig : constants.getFolderPaths()) {
            serverSpaceModels.add(getAvailableSpace(folderConfig));
        }
        //发送通知请求
        ServerModel serverModel = new ServerModel();
        serverModel.setLocalUrl(constants.getLocalUrl());
        serverModel.setServerSpaceModels(serverSpaceModels);
        //装载本地文件
        fileCacheService.updateServerInfo(serverModel);
    }

    /**
     * <p>获取目录可用空间</p>
     *
     * @param folderConfig 目录信息
     * @return 返回当前目录的可用空间
     */
    private ServerSpaceModel getAvailableSpace(FolderConfig folderConfig) {
        long size = 0;
        //计算缓存为上传完成文件大小
        Map<String, FileModel> fileInfoMap = constants.getFileInfoTable();
        for (String key : fileInfoMap.keySet()) {
            if (folderConfig.getPath().equals(fileInfoMap.get(key).getFilePath())) {
                size += fileInfoMap.get(key).getSize();
            }
        }
        File file = new File(folderConfig.getPath());
        //创建目录
        if (!file.exists()) {
            if (!file.mkdirs()) {
                log.error("初始化创建目录失败！");
            }
        }
        if (size == 0) {
            ServerSpaceModel serverSpaceModel = new ServerSpaceModel();
            serverSpaceModel.setPath(folderConfig.getPath());
            long availableSpace = file.getFreeSpace() - folderConfig.getReserveSpace();
            serverSpaceModel.setAvailableSpace(availableSpace);
            return serverSpaceModel;
        } else {
            ServerSpaceModel serverSpaceModel = new ServerSpaceModel();
            serverSpaceModel.setPath(folderConfig.getPath());
            long availableSpace = file.getFreeSpace() - folderConfig.getReserveSpace() - size;
            serverSpaceModel.setAvailableSpace(availableSpace);
            return serverSpaceModel;
        }
    }


    /**
     * 获取本地文件的hash信息
     *
     * @return 文件哈希信息
     */
    private List<HashModel> getHashModel() {
        List<HashModel> hashModels = new ArrayList<>();
        for (FolderConfig folderConfig : constants.getFolderPaths()) {
            String path = folderConfig.getPath() + File.separator;
            File[] files = new File(path).listFiles();
            if (files != null && files.length != 0) {
                for (File file : files) {
                    if (file.isFile()) {
                        String suffix = file.getName().substring(file.getName().indexOf("."), file.getName().length());
                        String hashCode = file.getName().substring(0, file.getName().indexOf("."));
                        if (FileSuffix.SUCCESS.getSuffix().equals(suffix)) {
                            hashModels.add(new HashModel(folderConfig.getPath(), hashCode, file.length()));
                        }
                    }
                }
            }
        }
        return hashModels;
    }

    /**
     * <p>同步本地数据到数据库</p>
     * <p>检测本地文件是否在hash表里存在，不存在创建hash信息，存在检测hash信息是否正确</p>
     * <p>hash表里的文件本地不存在则删除hash表里的信息</p>
     */
    private void initUpdateCreateFileHash() {
        // 所有本机的hash信息
        FileHashEntity fileHashEntity = new FileHashEntity();
        fileHashEntity.setServerUrl(constants.getLocalOldUrl());
        List<FileHashEntity> entities = fileHashMapper.selectList(new QueryWrapper<>(fileHashEntity));
        //获取本地文件的hash信息
        List<HashModel> hashModels = getHashModel();
        List<String> ids = new ArrayList<>();
        // 删除fileHash
        for (FileHashEntity fileHash : entities) {
            boolean bool = true;
            for (HashModel hashModel : hashModels) {
                if (fileHash.getHashCode().equals(hashModel.getHashCode())) {
                    bool = false;
                }
            }
            if (bool) {
                ids.add(fileHash.getId());
            }
        }
        // 删除文件不存在的hash值
        if (ids.size() > 0) {
            QueryWrapper<FileHashEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("id", ids);
            fileHashMapper.delete(queryWrapper);
        }
        // 修改创建fileHash
        List<String> hashCodes = new ArrayList<>();
        for (HashModel hashModel : hashModels) {
            boolean bool = true;
            for (FileHashEntity fileHash : entities) {
                if (hashModel.getHashCode().equals(fileHash.getHashCode())) {
                    bool = false;
                    if (!hashModel.getSize().equals(fileHash.getSize()) ||
                            !hashModel.getPath().equals(fileHash.getPath()) ||
                            !constants.getLocalUrl().equals(fileHash.getServerUrl())) {
                        fileHash.setServerUrl(constants.getLocalUrl());
                        fileHash.setPath(hashModel.getPath());
                        fileHash.setSize(hashModel.getSize());
                        fileHashMapper.updateById(fileHash);
                    }
                }
            }
            if (bool) { // 创建fileHash
                FileHashEntity fileHash = new FileHashEntity();
                fileHash.setServerUrl(constants.getLocalUrl());
                fileHash.setHashCode(hashModel.getHashCode());
                fileHash.setPath(hashModel.getPath());
                fileHash.setSize(hashModel.getSize());
                try {
                    fileHashMapper.insert(fileHash);
                } catch (DuplicateKeyException e) {
                    // 删除打包的零时文件
                    hashCodes.add(hashModel.getHashCode());
                }
            }
        }
        log.info("重复的文件源：{}", hashCodes);
    }

    /**
     * <p>初始化验证文件数据信息</p>
     * <p>检测服务器的文件是否有丢失</p>
     * <p>检测文件的信息和hash的信息是否存在错误</p>
     * <p>检测文件是否有冗余</p>
     */
    private void initVerifyFileHash() {
        //查出数据库数据
        List<FileEntity> fileList = fileService.list();
        List<String> fileIds = new ArrayList<>();
        List<FileEntity> entities = new ArrayList<>();
        for (FileEntity fileEntity : fileList) {
            if (EffectStatus.INVALID.getStatus().equals(fileEntity.getStatus())) {
                fileIds.add(fileEntity.getId());
            } else {
                entities.add(fileEntity);
            }
        }
        if (fileIds.size() > 0) {
            log.info("已删除失效的文件:{}", fileIds);
            fileService.removeByIds(fileIds);
        }
        List<FileHashEntity> fileHashCodes = fileHashMapper.selectList(new QueryWrapper<>());
        // 检测数据库文件是否存在
        Thread thread = new Thread() {
            @Override
            public void run() {
                List<String> errorCodes = new ArrayList<>();
                for (FileEntity fileEntity : entities) {
                    boolean bool = true;
                    for (FileHashEntity fileHashEntity : fileHashCodes) {
                        if (fileHashEntity.getHashCode().equals(fileEntity.getHashCode())) {
                            bool = false;
                        }
                    }
                    if (bool) {
                        errorCodes.add(fileEntity.getHashCode());
                    }
                }
                log.info("【严重】服务器文件丢失，异常数据:{}", errorCodes);
            }
        };
        thread.start();

        // 检测文件源是否被使用
        Thread thread2 = new Thread() {
            @Override
            public void run() {
                List<String> errorHashCodes = new ArrayList<>();
                List<String> sizeList = new ArrayList<>();
                for (FileHashEntity fileHashEntity : fileHashCodes) {
                    boolean bool = true;
                    for (FileEntity fileEntity : entities) {
                        if (fileHashEntity.getHashCode().equals(fileEntity.getHashCode())) {
                            bool = false;
                        }
                        if (fileHashEntity.getHashCode().equals(fileEntity.getHashCode()) && !fileHashEntity.getSize().equals(fileEntity.getSize())) {
                            sizeList.add(fileHashEntity.getHashCode());
                        }
                    }
                    if (bool) {
                        if (fileHashEntity.getServerUrl().equals(constants.getLocalUrl())) {
                            errorHashCodes.add(fileHashEntity.getHashCode());
                            fileHashMapper.deleteById(fileHashEntity.getId());
                            uploadService.deleteFile(fileHashEntity.getHashCode(), FileSuffix.SUCCESS.getSuffix());
                        }
                    }
                }
                log.info("【严重】文件的文件hash或size异常，异常数据:{}", sizeList);
                log.info("【提示】已清理的未使用文件，数据:{}", errorHashCodes);
            }
        };
        thread2.start();
    }
}
